/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008. All Rights Reserved.							  */
/* Open Source Software - may be modified and shared by FRC teams. The code   */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib.  */
/*----------------------------------------------------------------------------*/
#ifndef PWM_H_
#define PWM_H_

#include "SensorBase.h"

class DigitalModule;

/**
 * Class implements the PWM generation in the FPGA.
 * Values supplied as arguments for PWM outputs range from -1.0 to 1.0. They are mapped
 * to the hardware dependent values, in this case 0-255 for the FPGA.
 * Changes are immediately sent to the FPGA, and the update occurs at the next
 * FPGA cycle. There is no delay.
 * 
 * As of revision 0.1.4 of the FPGA, the FPGA interprets the 0-255 values as follows:
 *   255 = full "forward"
 *   254 to 129 = linear scaling from "full forward" to "center"
 *   128 = center value
 *   127 to 2 = linear scaling from "center" to "full reverse"
 *   1 = full "reverse"
 *   0 = disabled (i.e. PWM output is held low)
 */
class PWM : public SensorBase
{
	friend class DigitalModule;
public:
	typedef enum {kPeriodMultiplier_1X = 1, kPeriodMultiplier_2X = 2, kPeriodMultiplier_4X = 4} PeriodMultiplier;

	PWM(unsigned channel);
	PWM(unsigned slot, unsigned channel);
	~PWM();
	void SetRaw(unsigned char value);
	unsigned char GetRaw(void);
	void SetPeriodMultiplier(PeriodMultiplier mult);

protected:
	/**
	 * kDefaultPwmPeriod is "ticks" where each tick is 6.525us
	 * 20ms periods (50 Hz) are the "safest" setting in that this works for all devices
	 * 20ms periods seem to be desirable for Vex Motors
	 * 20ms periods are the specified period for HS-322HD servos, but work reliably down
	 *      to 10.0 ms; starting at about 8.5ms, the servo sometimes hums and get hot;
	 *      by 5.0ms the hum is nearly continuous
	 * 10ms periods work well for Victor 884
	 * 5ms periods allows higher update rates for Luminary Micro Jaguar speed controllers
	 * 
	 * This is the 1x period (5ms).  In hardware, the period scaling is implemented as an
	 *   output squelch to get longer periods for old devices.
	 * Set to 5 ms period / 6.525us clock = 766
	 */
	static const unsigned kDefaultPwmPeriod = 766;

	/**
	 * kDefaultMinPwmHigh is "ticks" where each tick is 6.525us
	 * There are 127 pwm values less than the center, so...
	 * The minimum output pulse length is 1.5ms - 127 * 6.525us = 0.671ms
	 * 0.671ms / 6.525us per tick = 103
	 */
	static const unsigned kDefaultMinPwmHigh = 103;

	static const int kPwmDisabled = 0;

	void SetMaxPositivePwm(int maxPositivePwm) {m_maxPositivePwm = maxPositivePwm;} ///< The maximum raw PWM value for forward direction.
	void SetMinPositivePwm(int minPositivePwm) {m_minPositivePwm = minPositivePwm;} ///< The minimum raw PWM value for forward direction.
	void SetCenterPwm(int centerPwm) {m_centerPwm = centerPwm;} ///< The raw PWM value that represents idle.
	void SetMaxNegativePwm(int maxNegativePwm) {m_maxNegativePwm = maxNegativePwm;} ///< The maximum raw PWM value for reverse direction.
	void SetMinNegativePwm(int minNegativePwm) {m_minNegativePwm = minNegativePwm;} ///< The minimum raw PWM value for reverse direction.
	void SetPosition(float pos);
	float GetPosition(void);
	void SetSpeed(float speed);
	float GetSpeed(void);

private:
	int GetPositiveScaleFactor(void) {return m_maxPositivePwm - m_minPositivePwm;} ///< The scale for positive speeds.
	int GetNegativeScaleFactor(void) {return m_maxNegativePwm - m_minNegativePwm;} ///< The scale for negative speeds.
	int GetFullRangeScaleFactor(void) {return m_maxPositivePwm - m_minNegativePwm;} ///< The scale for positions.
	void InitPWM(unsigned slot, unsigned channel);
	unsigned m_channel;
	DigitalModule *m_module;
	int m_maxPositivePwm;
	int m_minPositivePwm;
	int m_centerPwm;
	int m_maxNegativePwm;
	int m_minNegativePwm;
};

#endif
